/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package channelselectorservertest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Iterator;
import java.util.Set;

/**
 *
 * reference: http://kickjava.com/747.htm
 */
public class ChannelSelectorServerTest extends Thread {

    /**
     * @param args the command line arguments
     */
    public ChannelSelectorServerTest() {
    }

    @Override
    public void run() {

        try {
            System.out.println("Server is running...");
            // Create a selector object to monitor all open client connections.
            Selector selector = Selector.open();
            // Create a new non-blocking ServerSocketChannel, bind it to port 8000, and 
            // register it with the Selector 
            ServerSocketChannel server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.socket().bind(new InetSocketAddress(8000));
            SelectionKey serverkey = server.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("Waiting for connections...");
            //main loop
            while (true) {
                selector.select();//(nonblocking mode)
                //get set of keys that are ready for i/o
                Set keys = selector.selectedKeys();
                //loop through the selected keys 
                for (Iterator i = keys.iterator(); i.hasNext();) {
                    String cAddress = "";
                    String inputLine;

                    SelectionKey key = (SelectionKey) i.next();
                    i.remove();

                    if (key == serverkey) { // Activity on the ServerSocketChannel means a client is trying to connect to the server. 
                        if (key.isAcceptable()) {
                            SocketChannel client = server.accept();// Accept the client connection             
                            client.configureBlocking(false);// Put the client channel in non-blocking mode. 
                            SelectionKey clientkey = client.register(selector, SelectionKey.OP_READ);// Now register the client channel with the Selector object 
                            System.out.println("Accepting connection from sensor: " +client.socket().getPort());
                        }
                    } else {   // Otherwise, there must be activity on a client channel 
                        // Double-check that there is data to read 
                        if (!key.isReadable()) {
                            continue;
                        }
                        // Get the client channel that has data to read 
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buf = ByteBuffer.allocate(50);
                        
                        int bytesread = client.read(buf);
                        
                        ByteBuffer buf2 = buf;
                        buf2.flip();
                        client.write(buf2);//echo response

                        // If read (  )  returns -1, it indicates end-of-stream, which 
                        // means the client has disconnected, so de-register the 
                        // selection key and close the channel. 
                        if (bytesread == -1) {
                            key.cancel();
                            client.close();
                            continue;
                        } else {
                            cAddress = client.socket().getInetAddress().toString();
                            int cPort = client.socket().getPort();
                            byte array[] = buf.array();
                            String s = new String(array).trim();
                            System.out.println("Recieving data from sensor " + cPort+ " " +s);
                            //TODO save current data for given sensor
                        }
                    }
                }
            }
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    public static String myDecoder(ByteBuffer buffer, int size) {
        byte array[] = buffer.array();
        byte[] array2 = new byte[array.length * 2];
        for (int i = 0; i < array.length; i++) {
            array2[i] = 0;
            array2[i + 1] = array[i];
        }
        String s = new String(array2);
        return s;
    }

    public static ByteBuffer str_to_bb(String msg) {
        try {
            return encoder.encode(CharBuffer.wrap(msg));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String bytebufferToString(ByteBuffer buffer) {
        String data = "";
        try {
            int old_position = buffer.position();
            data = decoder.decode(buffer).toString();
            // reset buffer's position to its original so it is not altered:
            buffer.position(old_position);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return data;
    }
    public static Charset charset = Charset.forName("UTF-16");
    public static CharsetEncoder encoder = charset.newEncoder();
    public static CharsetDecoder decoder = charset.newDecoder();

    public static void main(String[] args) {
        ChannelSelectorServerTest instance = new ChannelSelectorServerTest();
        instance.start();
    }
}
